package com.songlanyun.modules.offlinegoods.service.impl;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.utils.BeanUtil;
import com.songlanyun.common.utils.PageUtils;
import com.songlanyun.common.utils.Query;
import com.songlanyun.modules.offlinegoods.dao.OfflineGoodsDao;
import com.songlanyun.modules.offlinegoods.dao.OfflineGoodsTypeDao;
import com.songlanyun.modules.offlinegoods.entity.OfflineGoods;
import com.songlanyun.modules.offlinegoods.entity.OfflineGoodsType;
import com.songlanyun.modules.offlinegoods.exception.OfflineGoodsTypeExceptionEnum;
import com.songlanyun.modules.offlinegoods.model.dto.OfflineGoodsTypeDTO;
import com.songlanyun.modules.offlinegoods.service.OfflineGoodsTypeService;
import com.songlanyun.modules.shop.service.ShopService;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

/**
 * 线下商品
 *
 * @author lijiahe
 * @date 2023-02-11
 */
@Service("offlineGoodsTypeService")
public class OfflineGoodsTypeServiceImpl extends ServiceImpl<OfflineGoodsTypeDao, OfflineGoodsType>
    implements OfflineGoodsTypeService {

    @Resource
    private OfflineGoodsDao offlineGoodsDao;

    @Autowired
    private ShopService shopService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OfflineGoodsType create(OfflineGoodsType entity) {
        baseMapper.insert(entity);
        return entity;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OfflineGoodsType modify(OfflineGoodsType entity) {
        baseMapper.updateById(entity);
        return entity;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(Long id) {
        baseMapper.deleteById(id);
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OfflineGoodsType> page =
            this.page(new Query<OfflineGoodsType>().getPage(params), this.getLambdaQueryWrapper(params));
        return new PageUtils(page);
    }

    @Override
    public List<OfflineGoodsType> queryList(Map<String, Object> params) {
        return this.list(this.getLambdaQueryWrapper(params));
    }

    private LambdaQueryWrapper<OfflineGoodsType> getLambdaQueryWrapper(Map<String, Object> params) {
        Long userId = MapUtil.getLong(params, "userId");
        Long shopId = MapUtil.getLong(params, "shopId");
        String name = MapUtil.getStr(params, "name");
        return new LambdaQueryWrapper<OfflineGoodsType>()
            .eq(ObjectUtil.isNotNull(userId), OfflineGoodsType::getCreateBy, userId)
            .eq(ObjectUtil.isNotNull(shopId), OfflineGoodsType::getShopId, shopId)
            .like(StrUtil.isNotBlank(name), OfflineGoodsType::getName, name)
            .orderByDesc(OfflineGoodsType::getCreateTime);
    }

    @Override
    public OfflineGoodsType loadOfflineGoodsTypeById(Long id, Boolean tw) {
        OfflineGoodsType offlineGoodsType = this.getById(id);
        if (offlineGoodsType == null && tw) {
            throw new RRException(OfflineGoodsTypeExceptionEnum.OFFLINE_GOODS_TYPE_NOT_EXISTS);
        }
        return offlineGoodsType;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveDto(OfflineGoodsTypeDTO dto) {
        if (ObjectUtil.isNull(dto)) {
            return;
        }
        this.validateNameExists(dto.getName(), dto.getShopId());
        OfflineGoodsType entity = new OfflineGoodsType();
        BeanUtil.copyPropertiesIgnoreNull(dto, entity);
        baseMapper.insert(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDto(Long shopId, OfflineGoodsTypeDTO dto) {
        if (ObjectUtil.isNull(dto)) {
            return;
        }
        OfflineGoodsType entity = this.loadOfflineGoodsTypeById(dto.getId(), true);
        this.validateOfflineGoodsTypeSafe(shopId, entity);

        if (!StrUtil.equals(dto.getName(), entity.getName())) {
            this.validateNameExists(dto.getName(), shopId);
        }
        BeanUtil.copyPropertiesIgnoreNull(dto, entity);
        baseMapper.updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteWithValidById(Long id, Long shopId, Boolean isValid) {
        OfflineGoodsType entity = this.loadOfflineGoodsTypeById(id, true);
        this.validateOfflineGoodsTypeSafe(shopId, entity);
        if (isValid) {
            OfflineGoods offlineGoods = offlineGoodsDao
                .selectOne(
                        new LambdaQueryWrapper<OfflineGoods>()
                                .eq(OfflineGoods::getTypeId, id)
                                .last("limit 1")
                );
            if (ObjectUtil.isNotNull(offlineGoods)) {
                throw new RRException(OfflineGoodsTypeExceptionEnum.OFFLINE_GOODS_TYPE_CANNOT_BE_DELETED);
            }
        }
        baseMapper.deleteById(id);
    }

    /**
     * 验证线下商品类型名称不能重复
     *
     * @param name
     */
    private void validateNameExists(String name, Long shopId) {
        OfflineGoodsType target = baseMapper
            .selectOne(new LambdaQueryWrapper<OfflineGoodsType>()
                    .eq(OfflineGoodsType::getName, name)
                    .eq(OfflineGoodsType::getShopId, shopId)
                    .last("limit 1"));
        if (target != null) {
            throw new RRException(OfflineGoodsTypeExceptionEnum.OFFLINE_GOODS_TYPE_REPEAT);
        }
    }

    /**
     *  只能操作自己的线下商品类型
     */
    private void validateOfflineGoodsTypeSafe(Long shopId, OfflineGoodsType offlineGoodsType) {
        if(!ObjectUtil.equal(offlineGoodsType.getShopId(), shopId)) {
            throw new RRException(OfflineGoodsTypeExceptionEnum.OFFLINE_GOODS_TYPE_SAFE);
        }
    }
}
